<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\Common\Robot\Robot;
use App\Common\Service\QwNotifyService;
use App\CustHub\Constants\QwNotifyChangeTypeConstants;
use App\CustHub\Constants\QwNotifyEventConstants;
use App\CustHub\Constants\SeatOrderStatusConstants;
use App\CustHub\Constants\UserMoneyLogTypeConstants;
use App\CustHub\Dto\QwNotifyDataDto;
use App\CustHub\Interfaces\OpenWorkApplicationInterface;
use App\CustHub\Mapper\ChCorpMapper;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChSeatMapper;
use App\CustHub\Model\ChCorp;
use App\CustHub\Model\ChRobot;
use App\CustHub\Model\ChSeat;
use App\CustHub\Model\ChSeatOrder;
use App\CustHub\Vo\UserBalanceVo;
use App\Robot\Service\RobotApiService;
use App\Setting\Service\SettingConfigService;
use Carbon\Carbon;
use FriendsOfHyperf\Lock\Exception\LockTimeoutException;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use function FriendsOfHyperf\Lock\lock;
use function Hyperf\Collection\collect;
use function Hyperf\Coroutine\co;

class LicenseService
{
    private string $buyUserId = 'AiTaoKe-LaoXu';

    #[Inject]
    protected OpenWorkApplicationInterface $openWorkApplication;

    #[Inject]
    protected UserBalanceService $userBalanceService;

    #[Inject]
    protected OpenOrderService $openOrderService;

    #[Inject]
    protected ChRobotMapper $robotMapper;

    #[Inject]
    protected ChSeatMapper $seatMapper;

    #[Inject]
    protected ChRobotService $robotService;

    protected array $testCorp = [];


    public function __construct()
    {
        $settingService = container()->get(SettingConfigService::class);
        $buyUserid = $settingService->getConfigByKey('buy_userid')['value'] ?? '';
        if(!empty($buyUserid)){
            $this->buyUserId = $buyUserid;
        }

        $testCorpStr = $settingService->getConfigByKey('test_corp')['value'] ?? '';
        if(!empty($testCorpStr)){
            $this->testCorp = explode(';',$testCorpStr);
        }
    }

    /**
     * 机器人登录后自动绑定接口许可证(登录成功后)
     * @param ChRobot $robot
     * @param string $userid
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function robotAutoBindHtSeat(ChRobot $robot,string $userid): bool
    {
        $seatInfo = ChSeat::query()
            ->where('main_uid',$robot->main_uid)
            ->where('userid',$userid)
            ->first();

        if($seatInfo){
            $this->robotMapper->update($robot->id,[
                'ht_bind_status' => 1,
                'ht_seat_id' => $seatInfo->id
            ]);
            $this->robotMapper->clearCache($robot->id);
            return true;
        }
        return false;
    }

    /**
     * 绑定席位
     * @param array $params
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[Transaction]
    public function bindLicense(array $params, bool $throwErr = true): bool
    {
        $robotInfo = $this->robotMapper->findById($params['id']);

        if($robotInfo->ht_bind_status == 1){
            throw new NormalStatusException("您已经绑定了席位，请勿重复绑定");
        }
        $userid = $robotInfo->userid;
        if(empty($userid)){
            if($robotInfo->login_status != 1){
                throw new NormalStatusException("请先登录企微号");
            }

            $userid = $this->robotService->getOpenid($robotInfo->id);
            if(empty($userid)){
                throw new NormalStatusException("绑定失败请重试");
            }
        }

        $seatId = $params['seat_id'];
        $seatInfo = ChSeat::query()
            ->where('id',$seatId)
            ->first();

        if(!$seatInfo){
            throw new NormalStatusException("请选择您要绑定的席位");
        }

        if($seatInfo->use_status == 1){
            throw new NormalStatusException("该席位正在使用中，请勿重复绑定");
        }

        if($this->checkLicense($seatInfo->auth_corp_id,$userid)){
            throw new NormalStatusException("您已经绑过席位了，解绑后才能绑定新的席位");
        }

        $this->openWorkApplication->activeAccount($seatInfo->code, $seatInfo->auth_corp_id, $userid);

        $this->robotMapper->update($robotInfo->id,[
            'ht_bind_status' => 1,
            'ht_seat_id' => $seatId
        ]);

        $this->seatMapper->update($seatInfo->id,[
            'use_status' => 1,
            'userid' => $userid,
            'bind_time' => Carbon::now()
        ]);

        $this->robotMapper->clearCache($robotInfo->id);

        $notifyData = (new QwNotifyDataDto())
            ->setEvent(QwNotifyEventConstants::CHANGE_SEAT)
            ->setChangeType(QwNotifyChangeTypeConstants::BIND_SEAT)
            ->setToUserName($seatInfo->auth_corp_id)
            ->setData([
                'userid' => $userid,
                'seat_id' => $seatId
            ]);
        container()->get(QwNotifyService::class)->pushQwWorkMessage($notifyData->toArray());
        return true;
    }

    public function batchBindLicense(array $params): void
    {
        $robotIds = $params['robot_ids'];
        if(!is_array($params['robot_ids'])){
            $robotIds = json_decode($params['robot_ids']);
        }

        $robotList = ChRobot::query()
            ->whereIn('id',$robotIds)
            ->where('ht_bind_status',0)
            ->get();

        if($robotList->isEmpty()){
            throw new NormalStatusException("请选择需要绑定席位的机器人");
        }

        $htSeatList = ChSeat::query()
            ->where('uid',$params['main_uid'])
            ->where('status',1)
            ->where('seat_type',1)
            ->where('use_status',0)
            ->get();

        if($htSeatList->isEmpty()){
            throw new NormalStatusException("互通账号席位不足，请购买席位后重试~");
        }

        co(function () use ($robotList){
            foreach ($robotList as $robotInfo){
                $lock = lock('robot_batch_bind_license_'.$robotInfo->id,6);
                try {
                    $lock->block(4);
                    if(!empty($robotInfo->userid)){
                        $rst = $this->robotAutoBindHtSeat($robotInfo,$robotInfo->userid);
                        if($rst){
                            continue;
                        }
                        $userid = $robotInfo->userid;
                    }else{
                        $open_user_id = $this->robotService->getOpenid($robotInfo->id);
                        if(!empty($open_user_id)){
                            $userid = $open_user_id;
                            $rst = $this->robotAutoBindHtSeat($robotInfo,$open_user_id);
                            if($rst){
                                continue;
                            }
                        }else{
                            continue;
                        }
                    }

                    $seatInfo = ChSeat::query()
                        ->where('uid',$robotInfo->main_uid)
                        ->where('corp_id',$robotInfo->corp_id)
                        ->where('seat_type',1)
                        ->where('status',1)
                        ->where('user_status',0)
                        ->first();
                    if(!$seatInfo){
                        continue;
                    }

                    $seatId = $seatInfo->id;

                    if($this->checkLicense($seatInfo->auth_corp_id,$userid)){
                        continue;
                    }

                    $this->openWorkApplication->activeAccount($seatInfo->code, $seatInfo->auth_corp_id, $userid);

                    $this->robotMapper->update($robotInfo->id,[
                        'ht_bind_status' => 1,
                        'ht_seat_id' => $seatId
                    ]);

                    $this->seatMapper->update($seatInfo->id,[
                        'use_status' => 1,
                        'userid' => $userid,
                        'bind_time' => Carbon::now()
                    ]);

                    $this->robotMapper->clearCache($robotInfo->id);

                    $notifyData = (new QwNotifyDataDto())
                        ->setEvent(QwNotifyEventConstants::CHANGE_SEAT)
                        ->setChangeType(QwNotifyChangeTypeConstants::BIND_SEAT)
                        ->setToUserName($seatInfo->auth_corp_id)
                        ->setData([
                            'userid' => $userid,
                            'seat_id' => $seatId
                        ]);
                    container()->get(QwNotifyService::class)->pushQwWorkMessage($notifyData->toArray());
                }catch (LockTimeoutException $e){
                    continue;
                }catch (\Throwable $e){
                    logger()->info('robot_id'.$robotInfo->id.'绑定失败'.$e->getMessage());
                    continue;
                } finally {
                    $lock->release();
                }
            }
        });
    }

    #[Transaction]
    public function changeBindLicense(array $params): bool
    {
        $robotInfo = $this->robotMapper->findById($params['id']);
        if($robotInfo->ht_bind_status != 1){
            throw new NormalStatusException("请先绑定席位");
        }

        $toRobotInfo = $this->robotMapper->findById($params['to_robot_id']);
        $toUserid = $toRobotInfo->userid;
        if(empty($toUserid)){
            if($toRobotInfo->login_status != 1){
                throw new NormalStatusException("请先登录企微号");
            }
            $service = make(Robot::class,[$toRobotInfo->server_id, $toRobotInfo->uuid])->gateway();
            $result = $service->useridToOpenuserid([$toRobotInfo->user_id]);
            if($result){
                $openUser = array_shift($result);
                $toUserid = $openUser['open_user_id'];
                $this->robotMapper->update($toRobotInfo->id,['userid' => $toUserid]);
                $this->robotMapper->clearCache($toRobotInfo->id);
            }else{
                throw new NormalStatusException("绑定失败请重试");
            }
        }

        $seatId = $robotInfo->ht_seat_id;

        $seatInfo = ChSeat::query()
            ->where('id',$seatId)
            ->first();

        if($seatInfo['expire_time'] < time()){
            throw new NormalStatusException("该席位已到期，请续费");
        }

        if($seatInfo['change_bind_time']){
            $next_change_bind_time = Carbon::now()->subDays(30)->timestamp;
            if($next_change_bind_time < strtotime($seatInfo['change_bind_time'])){
                throw new NormalStatusException("席位换绑后30天后才可进行下次换绑");
            }
        }

        $this->openWorkApplication->transferLicense($seatInfo->auth_corp_id, $robotInfo->userid,$toUserid);

        $this->seatMapper->update($seatInfo->id,[
            'userid' => $toUserid,
            'change_bind_time' => Carbon::now()
        ]);

        $this->robotMapper->update($robotInfo->id,[
            'ht_bind_status' => 0,
            'ht_seat_id' => null
        ]);

        $this->robotMapper->update($toRobotInfo->id,[
            'ht_bind_status' => 1,
            'ht_seat_id' => $seatId
        ]);

        $notifyData = (new QwNotifyDataDto())
            ->setEvent(QwNotifyEventConstants::CHANGE_SEAT)
            ->setChangeType(QwNotifyChangeTypeConstants::CHANGE_SEAT)
            ->setToUserName($seatInfo->auth_corp_id)
            ->setData([
                'employee_id' => $robotInfo->userid,
                'to_employee_id' => $toUserid,
                'seat_id' => $seatId
            ]);
        container()->get(QwNotifyService::class)->pushQwWorkMessage($notifyData->toArray());
        return true;
    }

    public function checkLicense(string $corpId,string $userid)
    {
        $result = $this->openWorkApplication->getActiveInfoByUser($corpId,$userid);

        if($result['errcode'] === 0 && $result['active_status'] == 1){
            //用户已激活
            $active_info_list = $result['active_info_list'];

            $activeInfo = collect($active_info_list)->filter(function ($item) use ($userid) {
                return $item['type'] == 2;
            })->first();

            if(empty($activeInfo)){
                return false;
            }

            $expireTime = Carbon::parse($activeInfo['expire_time'])->subDays(20)->timestamp;
            if($expireTime <= time()){
                return false;
            }
            return true;
        }
        return false;
    }

    public function createOrder(ChSeatOrder $order,mixed $transactionId): bool
    {
        try {
            $corpInfo = ChCorp::find($order->corp_id);
            if (!$corpInfo) {
                throw new \RuntimeException("企业信息不存在，corp_id: {$order->corp_id}");
            }

            if(in_array($corpInfo->auth_corp_id,$this->testCorp)){
                //测试企业最多创建1个月
                $order->month = 1;
            }

            $this->createOrderProcess($order, $transactionId, $corpInfo);
            return true;
        }catch (\Exception $e){
            // 统一错误处理（记录日志+退款）
            $this->handleOrderFailure($order, $e->getMessage());
            return true; // 保持原逻辑：最终返回true
        }
    }


    public function createRenewOrder(ChSeatOrder $order, mixed $transactionId): bool
    {
        try {
            // 获取企业信息和座位信息（带空值校验）
            $corpInfo = ChCorp::find($order->corp_id);
            $seatInfo = ChSeat::find($order->business_id);

            if (!$corpInfo) {
                throw new \RuntimeException("企业信息不存在，corp_id: {$order->corp_id}");
            }
            if (!$seatInfo) {
                throw new \RuntimeException("座位信息不存在，business_id: {$order->business_id}");
            }

            if(in_array($corpInfo->auth_corp_id,$this->testCorp)){
                //测试企业最多创建1个月
                $order->month = 1;
            }

            // 创建续费订单
            $this->createRenewOrderProcess($order, $transactionId, $corpInfo, $seatInfo);
            return true;

        } catch (\Exception $e) {
            // 统一错误处理（记录日志+退款）
            $this->handleOrderFailure($order, $e->getMessage());
            return true; // 保持原逻辑：最终返回true
        }
    }

    protected function createOrderProcess(
        ChSeatOrder $order,
                    $transactionId,
        ChCorp $corpInfo,
    ): void
    {
//        $durationDays = 0;
//        $seatCount = ChSeat::query()
//            ->where('main_uid',$order->uid)
//            ->where('type',1)
//            ->count();
//        $orderType = $seatCount == 0 ? 0 : 1;
//
//        if($orderType == 0){
//            $durationDays = $order->month * 30;
//        }
//        $userCount = $order->num;
//
//        // 步骤1: 创建开放平台收款订单
//        $openOrderResult = $this->openOrderService->paytoolOpenOrder(
//            $corpInfo->auth_corp_id,
//            $orderType, // 订单类型
//            $order->total_amount,
//            $userCount,
//            $durationDays
//        );
//
//        if (isset($openOrderResult['errcode']) && $openOrderResult['errcode'] !== 0) {
//            throw new \RuntimeException($openOrderResult['errmsg'] ?? '创建开放平台订单未知错误');
//        }
//
//        // 更新订单基础信息
//        $order->fill([
//            'skdd_order_id'    => $openOrderResult['order_id'],
//            'skdd_order_url'   => $openOrderResult['order_url'],
//            'skdd_origin_price' => $openOrderResult['origin_price'] ?? 0,
//            'skdd_paid_price'  => $openOrderResult['paid_price'] ?? 0,
//        ]);

        $orderId = $this->openWorkApplication->createNewOrder($corpInfo->auth_corp_id,$this->buyUserId,$order->num,$order->month);
        if($orderId === false){
            throw new \RuntimeException('接口许可证订单创建失败');
        }

        // 更新订单关联信息
        $order->fill([
            'transaction_id' => $transactionId,
            'order_id'      => $orderId
        ]);
        // 步骤4: 提交支付
        $this->processPayment($order, $orderId);
    }


    /**
     * 续费订单处理流程
     */
    protected function createRenewOrderProcess(
        ChSeatOrder $order,
                    $transactionId,
        ChCorp $corpInfo,
        ChSeat $seatInfo
    ): void {
        $accountList = [['userid' => $seatInfo->userid, 'type' => 2]];
        //todo 续费的情况先不创建 收款订单了 后续看怎么进行优化
//        $durationDays = $order->month * 30;

//        // 步骤1: 创建开放平台订单
//        $openOrderResult = $this->openOrderService->paytoolOpenOrder(
//            $corpInfo->auth_corp_id,
//            2, // 订单类型
//            $order->total_amount,
//            0,
//            $durationDays
//        );
//
//        if (isset($openOrderResult['errcode']) && $openOrderResult['errcode'] !== 0) {
//            throw new \RuntimeException($openOrderResult['errmsg'] ?? '创建开放平台订单未知错误');
//        }
//
//        // 更新订单基础信息
//        $order->fill([
//            'skdd_order_id'    => $openOrderResult['order_id'],
//            'skdd_order_url'   => $openOrderResult['order_url'],
//            'skdd_origin_price' => $openOrderResult['origin_price'] ?? 0,
//            'skdd_paid_price'  => $openOrderResult['paid_price'] ?? 0,
//        ]);

        // 步骤2: 创建续费任务
        $createResult = $this->openWorkApplication->createRenewOrderJob(
            $corpInfo->auth_corp_id,
            $accountList
        );

        if ($createResult['errcode'] !== 0) {
            throw new \RuntimeException($createResult['errmsg']);
        }

        // 步骤3: 提交订单任务
        $submitResult = $this->openWorkApplication->submitOrderJob(
            $createResult['jobid'],
            $this->buyUserId,
            ['months' => $order->month]
        );

        if ($submitResult['errcode'] !== 0) {
            throw new \RuntimeException($submitResult['errmsg']);
        }

        // 更新订单关联信息
        $order->fill([
            'transaction_id' => $transactionId,
            'order_id'      => $submitResult['order_id']
        ]);

        // 步骤4: 提交支付
        $this->processPayment($order, $submitResult['order_id']);
    }

    /**
     * 处理支付流程
     */
    protected function processPayment(ChSeatOrder $order, string $orderId): void
    {
        $response = $this->openWorkApplication->submitPayJob($this->buyUserId, $orderId);
        // 处理支付结果（包含特殊状态701162）
        if ($response['errcode'] !== 0 && $response['errcode'] !== 701162) {
            throw new \RuntimeException($response['errmsg']);
        }

        // 更新订单状态
        $order->status = SeatOrderStatusConstants::OPENING;
        if ($response['errcode'] !== 701162) {
            $order->jobid = $response['jobid'];
        }

        // 使用事务保存最终状态
        DB::transaction(function () use ($order) {
            $order->save();
        });
    }

    /**
     * 处理订单失败逻辑
     */
    protected function handleOrderFailure(ChSeatOrder $order, string $errorMsg): void
    {
        DB::transaction(function () use ($order, $errorMsg) {
            // 更新订单状态
            $order->update([
                'status'  => SeatOrderStatusConstants::REFUNDED,
                'err_msg' => substr($errorMsg, 0, 255) // 防止超长字符串
            ]);

            // 用户余额退款
            $balanceVo = new UserBalanceVo(
                $order->uid,
                (float)$order->pay_amount,
                UserMoneyLogTypeConstants::SEAT_REFUND,
                $order->id,
                $errorMsg
            );
            $this->userBalanceService->updateBalance($balanceVo);
        });

        // 记录错误日志（实际项目应使用日志组件）
        logger()->error('接口许可证创建失败', [
            'order_id' => $order->id,
            'error'    => $errorMsg
        ]);
    }

    /**
     * 创建互通账号席位
     * @param ChSeatOrder $order
     * @param string $orderId
     * @param string $cursor
     * @param int $limit
     * @return void
     */
    public function createSeat(ChSeatOrder $order,string $orderId,string $authCorpId,string $cursor = '',int $limit = 1000)
    {
        $result = $this->openWorkApplication->getListOrderAccount($orderId,$cursor,$limit);
        if($result['errcode'] == 0){
            $expireTime = Carbon::now()->addMonths($order->month)->timestamp;
            $accountList = $result['account_list'];
            $insertData = [];
            foreach ($accountList as $account){
                $insertData[] = [
                    'uid' => $order->uid,
                    'main_uid' => $order->uid,
                    'corp_id' => $order->corp_id,
                    'code' => $account['active_code'],
                    'expire_time' => $expireTime,
                    'type' => 1,
                    'seat_type' => 1,
                    'order_id' => $orderId,
                    'auth_corp_id' => $authCorpId,
                    'created_at' => Carbon::now(),
                    'updated_at' => Carbon::now(),
                ];
            }
            ChSeat::insert($insertData);
            if($result['has_more']){
                $this->createSeat($order,$orderId,$authCorpId,$result['next_cursor'],$limit);
            }
        }
    }

    public function renewSeat(ChSeatOrder $order,string $orderId,string $authCorpId,string $cursor = '',int $limit = 1000)
    {
        //目前仅支持一个账号
        $seatId = $order->business_id;
        $seatInfo = ChSeat::query()
            ->where('id',$seatId)
            ->first();
        if($seatInfo){
            $seatExpireTime = $seatInfo->expire_time;
            if($seatExpireTime < time()){
                $expireTime = Carbon::now()->addMonths($order->month)->timestamp;
            }else{
                $expireTime = Carbon::parse(date('Y-m-d H:i:s',$seatExpireTime))->addMonths($order->month)->timestamp;
            }
            $seatInfo->expire_time = $expireTime;
            $seatInfo->save();

            $corpInfo = ChCorp::query()
                ->where('id',$order->corp_id)
                ->first();

            $notifyData = (new QwNotifyDataDto())
                ->setEvent(QwNotifyEventConstants::CHANGE_SEAT)
                ->setChangeType(QwNotifyChangeTypeConstants::SEAT_RENEW)
                ->setToUserName($corpInfo->auth_corp_id)
                ->setData([
                    'id' => $seatId,
                    'expire_time' => $expireTime
                ]);
            container()->get(QwNotifyService::class)->pushQwWorkMessage($notifyData->toArray());
        }




//        $result = $this->openWorkApplication->getListOrderAccount($orderId,$cursor,$limit);
//        if($result['errcode'] == 0){
//            $expireTime = Carbon::now()->addMonths($order->month)->timestamp;
//            $accountList = $result['account_list'];
//            foreach ($accountList as $account){
//                ChSeat::query()
//                    ->where('userid',$account['userid'])
//                    ->update(
//                        [
//                            'expire_time' => $expireTime
//                        ]
//                    );
//            }
//            if($result['has_more']){
//                $this->renewSeat($order,$orderId,$authCorpId,$result['next_cursor'],$limit);
//            }
//        }
    }

    /**
     * 余额支付成功
     * @param string $orderId
     * @param string $authCorpId
     * @return void
     */
    public function paySuccess(string $orderId,string $authCorpId): void
    {
        $seatOrder = ChSeatOrder::query()
            ->where('order_id',$orderId)
            ->first();

        if(!empty($seatOrder)){
            $seatOrder->status = SeatOrderStatusConstants::PAID;
            $seatOrder->save();
            if($seatOrder->type == 0){
                $this->createSeat($seatOrder,$orderId,$authCorpId);
            }else{
                $this->renewSeat($seatOrder,$orderId,$authCorpId);
            }
        }
    }
}